//
// Created by LiuYou on 2021/8/22.
//

#include <cstdlib>
#include <pthread.h>
#include <cstdio>
#include <unistd.h>

static void* threadRoutine2(void*) {
//    sleep( 5 );

    pthread_t tid = pthread_self();
    fprintf( stdout, "\ntid = %lu\n", tid );
    fflush( nullptr );

    fprintf( stdout, "线程2正在工作......\n" );
    fflush( nullptr );

    pthread_exit( nullptr );
}


static void* threadRoutine(void*) {
//    sleep( 5 );

    pthread_t tid = pthread_self();
    fprintf( stdout, "\ntid = %lu\n", tid );
    fflush( nullptr );

    fprintf( stdout, "线程1正在工作......\n" );
    fflush( nullptr );

    pthread_exit( nullptr );
}


int main(int argc, char** argv) {
    pthread_t tid{};
    pthread_t tid2{};
    fflush( nullptr );
    pthread_create( &tid, nullptr, threadRoutine, nullptr );
    pthread_create( &tid2, nullptr, threadRoutine2, nullptr );

    pthread_t mainTid = pthread_self();
    fprintf( stdout, "mainTid = %lu\n", mainTid );
    fflush( nullptr );


    fprintf( stdout, "main线程正在工作......\n" );
    fflush( nullptr );


    pthread_join( tid, nullptr );
    pthread_join( tid2, nullptr );

    exit( 0 );
}



/*
todo 笔记: 跟多进程的调试差不多, 但是多线程不用多进程那样要 set设置一些内容再调试。而是通过
todo 笔记: CLion的Frames以及GDB配合使用就可以完成调试。
todo 笔记: 和多进程一样, 创建出来的线程调试结束后, CLion也是有问题。 不过线程这里不是程序直接退出, 而是在CLion中一直 connected。调试功能全部
todo 笔记: 变为了灰色。

todo 笔记: resume program execution(恢复程序执行)的使用(睛一闭运行，直到结束或者遇到下一个断点)。这个貌似可以解决线程和子进程返回main线程以及主进程的问题。
todo 笔记: 这创建的线程中返回main线程可以通过它, 但是子进程返回主进程时它还是没有用, 我试过了。

todo 笔记: resume program execution 这个按钮非常的重要，其作用为: 如果下面代码没有断点，那么回执行完全部代码；如果下面有代码，那么回跳转到下面的断点。
todo 笔记: 所以在多线程中可以用作返回。



// GDB调试信息。
Breakpoint 1, main (argc=1, argv=0x7fffffffe9d8) at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:42
42	    pthread_create( &tid, nullptr, threadRoutine, nullptr );
[New Thread 0x7ffff6ebb700 (LWP 61264)]
[New Thread 0x7ffff66ba700 (LWP 61265)]
(gdb) info threads
  Id   Target Id                                         Frame
* 1    Thread 0x7ffff7fe2740 (LWP 61214) "MultiThread01" main (argc=1, argv=0x7fffffffe9d8) at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:45
  2    Thread 0x7ffff6ebb700 (LWP 61264) "MultiThread01" threadRoutine () at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:27
  3    Thread 0x7ffff66ba700 (LWP 61265) "MultiThread01" threadRoutine2 () at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:13
todo 笔记: 多线程这里调试和多进程调试在CLion中有差别, 多进程调试如果不 set follow-fork-mode 和 detach-on-fork 的话, 默认调试的是主进程, 然后
todo 笔记: 子进程继续执行, 不会停下来。 而在多线程中, CLion在main线程创建出来其它线程后, 是不知道先执行那个线程的。所以每一次线程的调试可能
todo 笔记: 都是先进入了不同的线程中去调试。不过这也没有关系。使用 Frames和GDB就可以解决这个问题, 使CLion调试我们想调试的线程。
todo 笔记: 可能切换到或者进入到不同的线程进行调试的时候, 线程还没有启动, 还在一些汇编代码中, 这没有关系, 在GDB中输入n, 多输入几下n, 线程就会到
todo 笔记: 相关的启动例程函数那里(这个现象的原因应该是新创建出来的线程还没有执行到相应的启动例程函数那里, 我们在GDB中输入n, 再调试几步就到了。然后
todo 笔记: 在结合CLion的图形化界面。)。
(gdb) info threads
  Id   Target Id                                         Frame
  1    Thread 0x7ffff7fe2740 (LWP 61214) "MultiThread01" main (argc=1, argv=0x7fffffffe9d8) at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:45
* 2    Thread 0x7ffff6ebb700 (LWP 61264) "MultiThread01" threadRoutine () at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:27
  3    Thread 0x7ffff66ba700 (LWP 61265) "MultiThread01" threadRoutine2 () at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:13
todo 笔记: 比如这里我想调试 threadRoutine()这个线程, 我就在Frames那里切换到 Thread-2[MultiThread01], 然后在GDB中输入n, 即可就如这个
todo 笔记: 这个线程就行调试。
(gdb) n

Thread 2 "MultiThread01" hit Breakpoint 2, threadRoutine () at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:27
27	    pthread_t tid = pthread_self();
Thread 3 "MultiThread01" hit Breakpoint 7, threadRoutine2 () at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:13
13	    pthread_t tid = pthread_self();
(gdb) n
46	    fprintf( stdout, "mainTid = %lu\n", mainTid );

Thread 1 "MultiThread01" hit Breakpoint 3, main (argc=1, argv=0x7fffffffe9d8) at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiThread/Main.cpp:50
50	    fprintf( stdout, "main线程正在工作......\n" );
// todo 笔记: 这里使用 resume program后程序中所有的线程就全部退出了。
[Switching to thread 3 (Thread 0x7ffff66ba700 (LWP 61265))](running)
[Thread 0x7ffff66ba700 (LWP 61265) exited]
[Thread 0x7ffff6ebb700 (LWP 61264) exited]
[Inferior 1 (process 61214) exited normally]
// todo 笔记: 注意: 这里的 LWP 61265和61264是新创建出来的线程。而 process 61214即是 main线程。它肯定是最后一个退出的, 因为
// todo 笔记: 它要给其它线程收尸。谁创建出来的线程, 谁就负责为这个线程收尸。
// todo 笔记: 如果在  pthread_join()函数调用后面, main线程的exit()函数调用前面, 打一个断点。这时使用 resume program后, 是
// todo 笔记: 两个线程退出了, main线程在这个断点停下来。

// todo 笔记: 总结: 按照上面的方法就可以完成多线程的调试, 但是调试一个线程退出后, CLion会一直 connected, 所有的图形化调试全部变成灰色,
// todo 笔记: 就不能继续调试了。

 */